// Copyright Epic Games, Inc. All Rights Reserved.

#include "LyraAbilitySystemComponent.h"

#include "AbilitySystem/Abilities/LyraGameplayAbility.h"
#include "AbilitySystem/LyraAbilityTagRelationshipMapping.h"
#include "Animation/LyraAnimInstance.h"
#include "Engine/World.h"
#include "GameFramework/Pawn.h"
#include "LyraGlobalAbilitySystem.h"
#include "LyraLogChannels.h"
#include "System/LyraAssetManager.h"
#include "System/LyraGameData.h"

/**
 * Used to inline generated cpp files from UObject headers.
 * 
 * UE_INLINE_GENERATED_CPP_BY_NAME: 用于将头文件中的XXX.generated.h文件内联到CPP文件中。
 */
#include UE_INLINE_GENERATED_CPP_BY_NAME(LyraAbilitySystemComponent)

UE_DEFINE_GAMEPLAY_TAG(TAG_Gameplay_AbilityInputBlocked, "Gameplay.AbilityInputBlocked");

ULyraAbilitySystemComponent::ULyraAbilitySystemComponent(const FObjectInitializer& ObjectInitializer)
	: Super(ObjectInitializer)
{
	InputPressedSpecHandles.Reset();
	InputReleasedSpecHandles.Reset();
	InputHeldSpecHandles.Reset();

	/** 
	 * Copies count bytes of characters from Src to Dest. If some regions of the source
	 * area and the destination overlap, memmove ensures that the original source bytes
	 * in the overlapping region are copied before being overwritten.  NOTE: make sure
	 * that the destination buffer is the same size or larger than the source buffer!
	 */

	/**
	 * FMemory::Memset: 
	 * 从源到目的复制指定数量的字符字节。
	 * 如果源地址和目的地一些区域重叠，memmove确保在覆盖区域的原始资源字节再被覆盖之前是复制的。
	 * NOTE: 确保目的缓冲区是比源缓冲区相同或更大于源缓冲区。
	 * NOTE: 这是重置ActivationGroupCounts数组，从原来位置复制到新位置，并将初始值设置为0。
	 */
	FMemory::Memset(ActivationGroupCounts, 0, sizeof(ActivationGroupCounts));
}

void ULyraAbilitySystemComponent::EndPlay(const EEndPlayReason::Type EndPlayReason)
{
	/**
	 * Get a Subsystem of specified type from the provided GameInstance
	 * returns nullptr if the Subsystem cannot be found or the GameInstance is null
	 */

	/**
	 * UWorld::GetSubsystem<T>: 
	 * 获取具体类型的子系统从提供的游戏实例，如果子系统不存在或游戏实例是空则返回nullptr。
	 */
	if (ULyraGlobalAbilitySystem* GlobalAbilitySystem = UWorld::GetSubsystem<ULyraGlobalAbilitySystem>(GetWorld()))
	{
		/** Removes an ASC from the global system, along with any active global effects/abilities. */

		/** UnregisterASC: 从全局系统中移除ASC，与激活的全局效果/能力一起移除。 */
		GlobalAbilitySystem->UnregisterASC(this);
	}

	Super::EndPlay(EndPlayReason);
}

void ULyraAbilitySystemComponent::InitAbilityActorInfo(AActor* InOwnerActor, AActor* InAvatarActor)
{
	/** Cached off data about the owning actor that abilities will need to frequently access (movement component, mesh component, anim instance, etc) */

	/**
	 * AbilityActorInfo: 缓存所属Actor的能力数据，能力数据需要去频繁访问(移动组件，网格组件和动画实例等)。
	 */
	FGameplayAbilityActorInfo* ActorInfo = AbilityActorInfo.Get();
	check(ActorInfo);
	check(InOwnerActor);
	/**
	 * 为什么在Super::InitAbilityActorInfo(InOwnerActor, InAvatarActor);之前呢？
	 * 如果在Super::InitAbilityActorInfo(InOwnerActor, InAvatarActor);之后判断的话，就会导致bHasNewPawnAvatar
	 * 判断的是错误的，结果一定是false，因为判断的都是最新的了。
	 */
	const bool bHasNewPawnAvatar = Cast<APawn>(InAvatarActor) && (InAvatarActor != ActorInfo->AvatarActor);

	Super::InitAbilityActorInfo(InOwnerActor, InAvatarActor);

	if (bHasNewPawnAvatar)
	{
		// Notify all abilities that a new pawn avatar has been set

		// 通知所有能力一个新的Pawn化身被设置。

		/**
		 *	The abilities we can activate.
		 *		-This will include CDOs for non instanced abilities and per-execution instanced abilities.
		 *		-Actor-instanced abilities will be the actual instance (not CDO)
		 *
		 *	This array is not vital for things to work. It is a convenience thing for 'giving abilities to the actor'. But abilities could also work on things
		 *	without an AbilitySystemComponent. For example an ability could be written to execute on a StaticMeshActor. As long as the ability doesn't require
		 *	instancing or anything else that the AbilitySystemComponent would provide, then it doesn't need the component to function.
		 */

		/**
		 * ActivatableAbilities: 
		 * 我们能激活的能力。CDO是“Class Default Object”的缩写，即类默认对象。在游戏开发中，CDO代表了一种更通用、默认版本的技能，可根据游戏的需求进行引用或修改。
		 *  -这将会包含CDOs对于没有实例的能力和每次执行实例的能力。
		 *  -角色实例化的能力将会真实的实例化(没有CDO)。
		 */

		 /** List of activatable abilities */

		/** Items: 可激活的能力列表。 */
		for (const FGameplayAbilitySpec& AbilitySpec : ActivatableAbilities.Items)
		{
			/** Ability of the spec (Always the CDO. This should be const but too many things modify it currently) */

			/** Ability: 能力的规则(经常是CDO。这应该是const类型，但是当前大多数情况是修改它)。  */
			ULyraGameplayAbility* LyraAbilityCDO = CastChecked<ULyraGameplayAbility>(AbilitySpec.Ability);
			/** Returns how the ability is instanced when executed. This limits what an ability can do in its implementation. */

			/**
			 * GetInstancingPolicy: 
			 * 返回这个能力当被执行时怎么实例化的。这限制一个能力在它实现时能做的事。
			 */
			if (LyraAbilityCDO->GetInstancingPolicy() != EGameplayAbilityInstancingPolicy::NonInstanced)
			{
				/** Returns all instances, which can include instance per execution abilities */

				/**
				 * GetAbilityInstances: 返回所有实例，包含每次执行能力的实例。
				 */
				TArray<UGameplayAbility*> Instances = AbilitySpec.GetAbilityInstances();
				for (UGameplayAbility* AbilityInstance : Instances)
				{
					ULyraGameplayAbility* LyraAbilityInstance = CastChecked<ULyraGameplayAbility>(AbilityInstance);
					/** Called when the ability system is initialized with a pawn avatar. */

					/** OnPawnAvatarSet: 当能力系统被初始化在一个Pawn化身时回调。 */
					LyraAbilityInstance->OnPawnAvatarSet();
				}
			}
			else
			{
				LyraAbilityCDO->OnPawnAvatarSet();
			}
		}

		// Register with the global system once we actually have a pawn avatar. We wait until this time since some globally-applied effects may require an avatar.

		// 一旦我们有真实地Pawn化身将在全局系统注册。我们等待直到一些全局地应用的效果可能需要在化身上。
		if (ULyraGlobalAbilitySystem* GlobalAbilitySystem = UWorld::GetSubsystem<ULyraGlobalAbilitySystem>(GetWorld()))
		{
			/** Register an ASC with global system and apply any active global effects/abilities. */

			/** RegisterASC: 注册ASC在全局系统并且应用到任意激活全局效果/能力。 */
			GlobalAbilitySystem->RegisterASC(this);
		}

		if (ULyraAnimInstance* LyraAnimInst = Cast<ULyraAnimInstance>(ActorInfo->GetAnimInstance()))
		{
			/** InitializeWithAbilitySystem: 伴着能力系统初始化动画实例。 */
			LyraAnimInst->InitializeWithAbilitySystem(this);
		}

		TryActivateAbilitiesOnSpawn();
	}
}

void ULyraAbilitySystemComponent::TryActivateAbilitiesOnSpawn()
{
	/** ABILITYLIST_SCOPE_LOCK: 能力作用域锁定宏。 */
	ABILITYLIST_SCOPE_LOCK();
	for (const FGameplayAbilitySpec& AbilitySpec : ActivatableAbilities.Items)
	{
		const ULyraGameplayAbility* LyraAbilityCDO = CastChecked<ULyraGameplayAbility>(AbilitySpec.Ability);
		/**
		 * TryActivateAbilityOnSpawn: 尝试在孵化时激活能力。
		 */
		LyraAbilityCDO->TryActivateAbilityOnSpawn(AbilityActorInfo.Get(), AbilitySpec);
	}
}

void ULyraAbilitySystemComponent::CancelAbilitiesByFunc(TShouldCancelAbilityFunc ShouldCancelFunc, bool bReplicateCancelAbility)
{
	ABILITYLIST_SCOPE_LOCK();
	for (const FGameplayAbilitySpec& AbilitySpec : ActivatableAbilities.Items)
	{
		/** Returns true if this ability is active in any way */

		/** IsActive: 如果这个能力在任意方式是激活的，则返回True。 */
		if (!AbilitySpec.IsActive())
		{
			continue;
		}

		ULyraGameplayAbility* LyraAbilityCDO = CastChecked<ULyraGameplayAbility>(AbilitySpec.Ability);

		if (LyraAbilityCDO->GetInstancingPolicy() != EGameplayAbilityInstancingPolicy::NonInstanced)
		{
			// Cancel all the spawned instances, not the CDO.

			// 取消所有孵化的实例，不是CDO。
			TArray<UGameplayAbility*> Instances = AbilitySpec.GetAbilityInstances();
			for (UGameplayAbility* AbilityInstance : Instances)
			{
				ULyraGameplayAbility* LyraAbilityInstance = CastChecked<ULyraGameplayAbility>(AbilityInstance);

				if (ShouldCancelFunc(LyraAbilityInstance, AbilitySpec.Handle))
				{
					/** Returns true if this ability can be canceled */

					/**
					 * CanBeCanceled: 如果这个能力能被取消则返回True。
					 */
					if (LyraAbilityInstance->CanBeCanceled())
					{
						/** Destroys instanced-per-execution abilities. Instance-per-actor abilities should 'reset'. Any active ability state tasks receive the 'OnAbilityStateInterrupted' event. Non instance abilities - what can we do? */

						/**
						 * CancelAbility: 
						 * 销毁实例化的每次执行能力。实例化每个Actor应该被重置。
						 * 任何激活的能力状态任务接收OnAbilityStateInterrupted事件。
						 */

						 /** Gets the current activation info bound to this ability - can only be called on instanced abilities. */

						/** GetCurrentActivationInfo: 获取当前绑定到能力的激活信息 - 仅能在实例化的能力被调用。 */
						LyraAbilityInstance->CancelAbility(AbilitySpec.Handle, AbilityActorInfo.Get(), LyraAbilityInstance->GetCurrentActivationInfo(), bReplicateCancelAbility);
					}
					else
					{
						UE_LOG(LogLyraAbilitySystem, Error, TEXT("CancelAbilitiesByFunc: Can't cancel ability [%s] because CanBeCanceled is false."), *LyraAbilityInstance->GetName());
					}
				}
			}
		}
		else
		{
			// Cancel the non-instanced ability CDO.
			if (ShouldCancelFunc(LyraAbilityCDO, AbilitySpec.Handle))
			{
				// Non-instanced abilities can always be canceled.
				check(LyraAbilityCDO->CanBeCanceled());
				LyraAbilityCDO->CancelAbility(AbilitySpec.Handle, AbilityActorInfo.Get(), FGameplayAbilityActivationInfo(), bReplicateCancelAbility);
			}
		}
	}
}

void ULyraAbilitySystemComponent::CancelInputActivatedAbilities(bool bReplicateCancelAbility)
{
	auto ShouldCancelFunc = [this](const ULyraGameplayAbility* LyraAbility, FGameplayAbilitySpecHandle Handle)
	{
		// Defines how this ability is meant to activate.

		// GetActivationPolicy: 获取能力怎样激活是有意义的。
		const ELyraAbilityActivationPolicy ActivationPolicy = LyraAbility->GetActivationPolicy();
		return ((ActivationPolicy == ELyraAbilityActivationPolicy::OnInputTriggered) || (ActivationPolicy == ELyraAbilityActivationPolicy::WhileInputActive));
	};

	CancelAbilitiesByFunc(ShouldCancelFunc, bReplicateCancelAbility);
}

void ULyraAbilitySystemComponent::AbilitySpecInputPressed(FGameplayAbilitySpec& Spec)
{
	/** Called on local player always. Called on server only if bReplicateInputDirectly is set on the GameplayAbility. */

	/** AbilitySpecInputPressed: 本地玩家经常调用。如果在玩法能力的bReplicateInputDirectly是被设置的，则仅在服务端调用。 */
	/**
	 * 在游戏开发中，尤其是涉及多人联机游戏时，本地玩家端和服务器端的逻辑处理是有区别的。
	 * 本地玩家端主要负责处理玩家的输入、渲染画面等与玩家直接交互的操作。
	 * 而服务器端则负责维护游戏的公平性、一致性和权威性，处理游戏中的各种逻辑并同步给各个客户端。
	 */
	Super::AbilitySpecInputPressed(Spec);

	// We don't support UGameplayAbility::bReplicateInputDirectly.
	// Use replicated events instead so that the WaitInputPress ability task works.

	// 我们不支持UGameplayAbility::bReplicateInputDirectly。
	// 使用复制的事件替换，如此WaitInputPress能力任务工作。
	if (Spec.IsActive())
	{
		// Invoke the InputPressed event. This is not replicated here. If someone is listening, they may replicate the InputPressed event to the server.

		// 触发这个输入按下事件。这将不会在这复制。如果某人正在监听，它们也许会复制这个输入按下事件到服务端。

		/** Returns prediction key, const to avoid being able to modify it after creation */

		/** GetActivationPredictionKey: 返回预测键，常量能够避免在创造之后被修改。 */
		InvokeReplicatedEvent(EAbilityGenericReplicatedEvent::InputPressed, Spec.Handle, Spec.ActivationInfo.GetActivationPredictionKey());
	}
}

void ULyraAbilitySystemComponent::AbilitySpecInputReleased(FGameplayAbilitySpec& Spec)
{
	Super::AbilitySpecInputReleased(Spec);

	// We don't support UGameplayAbility::bReplicateInputDirectly.
	// Use replicated events instead so that the WaitInputRelease ability task works.
	if (Spec.IsActive())
	{
		// Invoke the InputReleased event. This is not replicated here. If someone is listening, they may replicate the InputReleased event to the server.
		InvokeReplicatedEvent(EAbilityGenericReplicatedEvent::InputReleased, Spec.Handle, Spec.ActivationInfo.GetActivationPredictionKey());
	}
}

void ULyraAbilitySystemComponent::AbilityInputTagPressed(const FGameplayTag& InputTag)
{
	if (InputTag.IsValid())
	{
		for (const FGameplayAbilitySpec& AbilitySpec : ActivatableAbilities.Items)
		{
			/** Optional ability tags that are replicated.  These tags are also captured as source tags by applied gameplay effects. */

			/** DynamicAbilityTags: 可选择的、被复制的能力标签。这些标签是被捕获的，作为应用效果的源标签。 */
			if (AbilitySpec.Ability && (AbilitySpec.DynamicAbilityTags.HasTagExact(InputTag)))
			{
				InputPressedSpecHandles.AddUnique(AbilitySpec.Handle);
				InputHeldSpecHandles.AddUnique(AbilitySpec.Handle);
			}
		}
	}
}

void ULyraAbilitySystemComponent::AbilityInputTagReleased(const FGameplayTag& InputTag)
{
	if (InputTag.IsValid())
	{
		for (const FGameplayAbilitySpec& AbilitySpec : ActivatableAbilities.Items)
		{
			if (AbilitySpec.Ability && (AbilitySpec.DynamicAbilityTags.HasTagExact(InputTag)))
			{
				InputReleasedSpecHandles.AddUnique(AbilitySpec.Handle);
				InputHeldSpecHandles.Remove(AbilitySpec.Handle);
			}
		}
	}
}

void ULyraAbilitySystemComponent::ProcessAbilityInput(float DeltaTime, bool bGamePaused)
{
	/**
	 * Check if the count container has a gameplay tag that matches against the specified tag (expands to include parents of asset tags).
	 * 
	 * HasMatchingGameplayTag: 检查计数容器中是否存在与指定标签相匹配的游戏玩法标签(扩展范围以包含资产标签的父标签)。
	 */
	if (HasMatchingGameplayTag(TAG_Gameplay_AbilityInputBlocked))
	{
		ClearAbilityInput();
		return;
	}
	/**
	 * AbilitiesToActivate: 20250504理解是用来处理由于输入事件还没激活的能力的数组。
	 */
	static TArray<FGameplayAbilitySpecHandle> AbilitiesToActivate;
	AbilitiesToActivate.Reset();

	//@TODO: See if we can use FScopedServerAbilityRPCBatcher ScopedRPCBatcher in some of these loops

	//@TODO: 在同样的循环中是否能使用FScopedServerAbilityRPCBatcher ScopedRPCBatcher。

	//
	// Process all abilities that activate when the input is held.
	//

	// 当输入被持有时处理所有激活的能力。
	for (const FGameplayAbilitySpecHandle& SpecHandle : InputHeldSpecHandles)
	{
		/** Returns an ability spec from a handle. If modifying call MarkAbilitySpecDirty */

		/** FindAbilitySpecFromHandle: 从句柄中返回能力规则。如果修改，调用MarkAbilitySpecDirty修改。 */
		if (const FGameplayAbilitySpec* AbilitySpec = FindAbilitySpecFromHandle(SpecHandle))
		{
			if (AbilitySpec->Ability && !AbilitySpec->IsActive())
			{
				const ULyraGameplayAbility* LyraAbilityCDO = CastChecked<ULyraGameplayAbility>(AbilitySpec->Ability);

				if (LyraAbilityCDO->GetActivationPolicy() == ELyraAbilityActivationPolicy::WhileInputActive)
				{
					AbilitiesToActivate.AddUnique(AbilitySpec->Handle);
				}
			}
		}
	}

	//
	// Process all abilities that had their input pressed this frame.
	//

	// 处理所有在此帧输入按压的能力。
	for (const FGameplayAbilitySpecHandle& SpecHandle : InputPressedSpecHandles)
	{
		if (FGameplayAbilitySpec* AbilitySpec = FindAbilitySpecFromHandle(SpecHandle))
		{
			if (AbilitySpec->Ability)
			{
				/** Is input currently pressed. Set to false when input is released */

				/** InputPressed: 设置为True，表示当前输入是被按下。设置为False表示当前输入被抬起。 */
				AbilitySpec->InputPressed = true;

				if (AbilitySpec->IsActive())
				{
					// Ability is active so pass along the input event.

					// 能力是激活的如此传递到输入事件。
					AbilitySpecInputPressed(*AbilitySpec);
				}
				else
				{
					const ULyraGameplayAbility* LyraAbilityCDO = CastChecked<ULyraGameplayAbility>(AbilitySpec->Ability);

					if (LyraAbilityCDO->GetActivationPolicy() == ELyraAbilityActivationPolicy::OnInputTriggered)
					{
						AbilitiesToActivate.AddUnique(AbilitySpec->Handle);
					}
				}
			}
		}
	}

	//
	// Try to activate all the abilities that are from presses and holds.
	// We do it all at once so that held inputs don't activate the ability
	// and then also send a input event to the ability because of the press.
	//

	/**
	 * 尝试去激活所有的按压和持有的能力。
	 * 我们立即处理它，如此持有输入不会激活的能力并且这时也发送输入事件因为按压。
	 * NOTE: 就是说，激活所有按下和长按操作的技能，这样就避免了由于持续按下再次激活能力。
	 */
	for (const FGameplayAbilitySpecHandle& AbilitySpecHandle : AbilitiesToActivate)
	{
		/**
		 * Attempts to activate the given ability, will check costs and requirements before doing so.
		 * Returns true if it thinks it activated, but it may return false positives due to failure later in activation.
		 * If bAllowRemoteActivation is true, it will remotely activate local/server abilities, if false it will only try to locally activate the ability
		 */

		/**
		 * TryActivateAbility: 
		 * 尝试去激活给定能力，在执行之前将会检查消耗和需求。
		 * 如果它认为它被激活，则返回True，但是它也可能返回False，极有可能导致在之后的激活中失败。
		 * 如果bAllowRemoteActivation是True，它将会远程地激活本地或服务器能力，如果为False，它将只会激活本地能力。
		 */
		TryActivateAbility(AbilitySpecHandle);
	}

	//
	// Process all abilities that had their input released this frame.
	//

	// 处理在这帧时输入事件抬起的所有能力。
	for (const FGameplayAbilitySpecHandle& SpecHandle : InputReleasedSpecHandles)
	{
		if (FGameplayAbilitySpec* AbilitySpec = FindAbilitySpecFromHandle(SpecHandle))
		{
			if (AbilitySpec->Ability)
			{
				AbilitySpec->InputPressed = false;

				if (AbilitySpec->IsActive())
				{
					// Ability is active so pass along the input event.
					AbilitySpecInputReleased(*AbilitySpec);
				}
			}
		}
	}

	//
	// Clear the cached ability handles.
	//

	// 清空缓存的能力句柄。
	InputPressedSpecHandles.Reset();
	InputReleasedSpecHandles.Reset();
}

void ULyraAbilitySystemComponent::ClearAbilityInput()
{
	InputPressedSpecHandles.Reset();
	InputReleasedSpecHandles.Reset();
	InputHeldSpecHandles.Reset();
}

void ULyraAbilitySystemComponent::NotifyAbilityActivated(const FGameplayAbilitySpecHandle Handle, UGameplayAbility* Ability)
{
	/** A generic callback anytime an ability is activated (started) */

	/**
	 * void UAbilitySystemComponent::NotifyAbilityActivated(FGameplayAbilitySpecHandle Handle, UGameplayAbility* Ability)
   * {
	 *   AbilityActivatedCallbacks.Broadcast(Ability);
   * }
	 * FGenericAbilityDelegate: 
	 * 在任意时刻能力被激活时的普遍回调。
	 */
	Super::NotifyAbilityActivated(Handle, Ability);

	ULyraGameplayAbility* LyraAbility = CastChecked<ULyraGameplayAbility>(Ability);

	AddAbilityToActivationGroup(LyraAbility->GetActivationGroup(), LyraAbility);
}

void ULyraAbilitySystemComponent::NotifyAbilityFailed(const FGameplayAbilitySpecHandle Handle, UGameplayAbility* Ability, const FGameplayTagContainer& FailureReason)
{
	/**
	 * Called with a failure reason when an ability fails to activate.
	 * 
	 * void UAbilitySystemComponent::NotifyAbilityFailed(const FGameplayAbilitySpecHandle Handle, UGameplayAbility* Ability, const FGameplayTagContainer& FailureReason)
   * {
	 *   AbilityFailedCallbacks.Broadcast(Ability, FailureReason);
   * }
	 * FAbilityFailedDelegate: 
	 * 当能力激活失败并伴有失败原因时回调。
	 */
	Super::NotifyAbilityFailed(Handle, Ability, FailureReason);

	/** Returns the avatar actor for this component */

	/** GetAvatarActor: 获取此组件的化身Actor。 */
	if (APawn* Avatar = Cast<APawn>(GetAvatarActor()))
	{
		/**
		 * IsSupportedForNetworking: 此能力是否支持网络功能。
		 */
		if (!Avatar->IsLocallyControlled() && Ability->IsSupportedForNetworking())
		{
			ClientNotifyAbilityFailed(Ability, FailureReason);
			return;
		}
	}

	HandleAbilityFailed(Ability, FailureReason);
}

void ULyraAbilitySystemComponent::NotifyAbilityEnded(FGameplayAbilitySpecHandle Handle, UGameplayAbility* Ability, bool bWasCancelled)
{
	/** Called from the ability to let the component know it is ended */

	/** NotifyAbilityEnded: 让组件知道能力结束时调用。 */
	Super::NotifyAbilityEnded(Handle, Ability, bWasCancelled);

	ULyraGameplayAbility* LyraAbility = CastChecked<ULyraGameplayAbility>(Ability);
	/** RemoveAbilityFromActivationGroup: 从激活的能力组中移除能力。 */
	RemoveAbilityFromActivationGroup(LyraAbility->GetActivationGroup(), LyraAbility);
}

void ULyraAbilitySystemComponent::ApplyAbilityBlockAndCancelTags(const FGameplayTagContainer& AbilityTags, UGameplayAbility* RequestingAbility, bool bEnableBlockTags, const FGameplayTagContainer& BlockTags, bool bExecuteCancelTags, const FGameplayTagContainer& CancelTags)
{
	FGameplayTagContainer ModifiedBlockTags = BlockTags;
	FGameplayTagContainer ModifiedCancelTags = CancelTags;

	if (TagRelationshipMapping)
	{
		// Use the mapping to expand the ability tags into block and cancel tag

		// 使用映射去暴露能力标签到阻塞和取消标签容器内。

		/** Given a set of ability tags, parse the tag relationship and fill out tags to block and cancel */

		/** GetAbilityTagsToBlockAndCancel: 给定能力标签集合，分析标签关系并且填入到阻塞和取消标签容器中。 */
		TagRelationshipMapping->GetAbilityTagsToBlockAndCancel(AbilityTags, &ModifiedBlockTags, &ModifiedCancelTags);
	}
	/**
	 * Called from ability activation or native code, will apply the correct ability blocking tags and cancel existing abilities. Subclasses can override the behavior
	 *
	 * @param AbilityTags The tags of the ability that has block and cancel flags
	 * @param RequestingAbility The gameplay ability requesting the change, can be NULL for native events
	 * @param bEnableBlockTags If true will enable the block tags, if false will disable the block tags
	 * @param BlockTags What tags to block
	 * @param bExecuteCancelTags If true will cancel abilities matching tags
	 * @param CancelTags what tags to cancel
	 */

	/**
	 * 从能力激活或原始代码中回调，将会应用正确的能力阻塞标签和取消存在能力。子类能够覆盖这一行为。
	 */
	Super::ApplyAbilityBlockAndCancelTags(AbilityTags, RequestingAbility, bEnableBlockTags, ModifiedBlockTags, bExecuteCancelTags, ModifiedCancelTags);

	//@TODO: Apply any special logic like blocking input or movement

	//@TODO: 应用具体的逻辑像阻塞输入或移动。
}

void ULyraAbilitySystemComponent::HandleChangeAbilityCanBeCanceled(const FGameplayTagContainer& AbilityTags, UGameplayAbility* RequestingAbility, bool bCanBeCanceled)
{
	/** Called when an ability is cancellable or not. Doesn't do anything by default, can be overridden to tie into gameplay events */

	/** HandleChangeAbilityCanBeCanceled: 当一个能力是否可取消时被调用。默认不会做任何事，能够被覆盖去联系游戏玩法事件。 */
	Super::HandleChangeAbilityCanBeCanceled(AbilityTags, RequestingAbility, bCanBeCanceled);

	//@TODO: Apply any special logic like blocking input or movement

	//@TODO: 应用具体的逻辑像阻塞输入或移动。
}

void ULyraAbilitySystemComponent::GetAdditionalActivationTagRequirements(const FGameplayTagContainer& AbilityTags, FGameplayTagContainer& OutActivationRequired, FGameplayTagContainer& OutActivationBlocked) const
{
	if (TagRelationshipMapping)
	{
		/** Given a set of ability tags, add additional required and blocking tags */

		/** GetRequiredAndBlockedActivationTags: 给定能力标签集合，添加额外的需求和阻塞标签。 */
		TagRelationshipMapping->GetRequiredAndBlockedActivationTags(AbilityTags, &OutActivationRequired, &OutActivationBlocked);
	}
}

void ULyraAbilitySystemComponent::SetTagRelationshipMapping(ULyraAbilityTagRelationshipMapping* NewMapping)
{
	TagRelationshipMapping = NewMapping;
}

void ULyraAbilitySystemComponent::ClientNotifyAbilityFailed_Implementation(const UGameplayAbility* Ability, const FGameplayTagContainer& FailureReason)
{
	HandleAbilityFailed(Ability, FailureReason);
}

void ULyraAbilitySystemComponent::HandleAbilityFailed(const UGameplayAbility* Ability, const FGameplayTagContainer& FailureReason)
{
	//UE_LOG(LogLyraAbilitySystem, Warning, TEXT("Ability %s failed to activate (tags: %s)"), *GetPathNameSafe(Ability), *FailureReason.ToString());

	if (const ULyraGameplayAbility* LyraAbility = Cast<const ULyraGameplayAbility>(Ability))
	{
		/**
		 * OnAbilityFailedToActivate: 当能力激活失败时调用。
		 */
		LyraAbility->OnAbilityFailedToActivate(FailureReason);
	}	
}

bool ULyraAbilitySystemComponent::IsActivationGroupBlocked(ELyraAbilityActivationGroup Group) const
{
	bool bBlocked = false;

	switch (Group)
	{
	case ELyraAbilityActivationGroup::Independent:
		// Independent abilities are never blocked.

		// 独立能力从不阻塞。
		bBlocked = false;
		break;

	case ELyraAbilityActivationGroup::Exclusive_Replaceable:
	case ELyraAbilityActivationGroup::Exclusive_Blocking:
		// Exclusive abilities can activate if nothing is blocking.

		// 如果没有任何阻塞，独裁能力能激活。
		bBlocked = (ActivationGroupCounts[(uint8)ELyraAbilityActivationGroup::Exclusive_Blocking] > 0);
		break;

	default:
		checkf(false, TEXT("IsActivationGroupBlocked: Invalid ActivationGroup [%d]\n"), (uint8)Group);
		break;
	}

	return bBlocked;
}

void ULyraAbilitySystemComponent::AddAbilityToActivationGroup(ELyraAbilityActivationGroup Group, ULyraGameplayAbility* LyraAbility)
{
	check(LyraAbility);
	check(ActivationGroupCounts[(uint8)Group] < INT32_MAX);

	ActivationGroupCounts[(uint8)Group]++;

	const bool bReplicateCancelAbility = false;

	switch (Group)
	{
	case ELyraAbilityActivationGroup::Independent:
		// Independent abilities do not cancel any other abilities.

		// 独立能力不能取消任何其他能力。
		break;

	case ELyraAbilityActivationGroup::Exclusive_Replaceable:
	case ELyraAbilityActivationGroup::Exclusive_Blocking:
		CancelActivationGroupAbilities(ELyraAbilityActivationGroup::Exclusive_Replaceable, LyraAbility, bReplicateCancelAbility);
		break;

	default:
		checkf(false, TEXT("AddAbilityToActivationGroup: Invalid ActivationGroup [%d]\n"), (uint8)Group);
		break;
	}

	const int32 ExclusiveCount = ActivationGroupCounts[(uint8)ELyraAbilityActivationGroup::Exclusive_Replaceable] + ActivationGroupCounts[(uint8)ELyraAbilityActivationGroup::Exclusive_Blocking];
	if (!ensure(ExclusiveCount <= 1))
	{
		UE_LOG(LogLyraAbilitySystem, Error, TEXT("AddAbilityToActivationGroup: Multiple exclusive abilities are running."));
	}
}

void ULyraAbilitySystemComponent::RemoveAbilityFromActivationGroup(ELyraAbilityActivationGroup Group, ULyraGameplayAbility* LyraAbility)
{
	check(LyraAbility);
	check(ActivationGroupCounts[(uint8)Group] > 0);

	ActivationGroupCounts[(uint8)Group]--;
}

void ULyraAbilitySystemComponent::CancelActivationGroupAbilities(ELyraAbilityActivationGroup Group, ULyraGameplayAbility* IgnoreLyraAbility, bool bReplicateCancelAbility)
{
	auto ShouldCancelFunc = [this, Group, IgnoreLyraAbility](const ULyraGameplayAbility* LyraAbility, FGameplayAbilitySpecHandle Handle)
	{
		// Defines the relationship between this ability activating and other abilities activating.

		// GetActivationGroup: 获取激活的能力和其他能力的关系。
		return ((LyraAbility->GetActivationGroup() == Group) && (LyraAbility != IgnoreLyraAbility));
	};

	CancelAbilitiesByFunc(ShouldCancelFunc, bReplicateCancelAbility);
}

void ULyraAbilitySystemComponent::AddDynamicTagGameplayEffect(const FGameplayTag& Tag)
{
	// Returns the subclass referenced by a TSoftClassPtr.  This will synchronously load the asset if it's not already loaded.

	// GetSubclass: 返回TSoftClassPtr的子类引用。如果没有导入将会异步导入资产。
	const TSubclassOf<UGameplayEffect> DynamicTagGE = ULyraAssetManager::GetSubclass(ULyraGameData::Get().DynamicTagGameplayEffect);
	if (!DynamicTagGE)
	{
		UE_LOG(LogLyraAbilitySystem, Warning, TEXT("AddDynamicTagGameplayEffect: Unable to find DynamicTagGameplayEffect [%s]."), *ULyraGameData::Get().DynamicTagGameplayEffect.GetAssetName());
		return;
	}

	const FGameplayEffectSpecHandle SpecHandle = MakeOutgoingSpec(DynamicTagGE, 1.0f, MakeEffectContext());
	FGameplayEffectSpec* Spec = SpecHandle.Data.Get();

	if (!Spec)
	{
		UE_LOG(LogLyraAbilitySystem, Warning, TEXT("AddDynamicTagGameplayEffect: Unable to make outgoing spec for [%s]."), *GetNameSafe(DynamicTagGE));
		return;
	}
	/** Tags that are granted and that did not come from the UGameplayEffect def. These are replicated. */

	/** DynamicGrantedTags: 标签，被赋予的标签并且不是来自UGameplayEffect定义的标签。这是能被复制到其他客户端或服务器。 */
	Spec->DynamicGrantedTags.AddTag(Tag);
	/** Applies a previously created gameplay effect spec to this component */

	/** ApplyGameplayEffectSpecToSelf: 应用一个原始地创造的游戏玩法效果规则到组件。 */
	ApplyGameplayEffectSpecToSelf(*Spec);
}

void ULyraAbilitySystemComponent::RemoveDynamicTagGameplayEffect(const FGameplayTag& Tag)
{
	const TSubclassOf<UGameplayEffect> DynamicTagGE = ULyraAssetManager::GetSubclass(ULyraGameData::Get().DynamicTagGameplayEffect);
	if (!DynamicTagGE)
	{
		UE_LOG(LogLyraAbilitySystem, Warning, TEXT("RemoveDynamicTagGameplayEffect: Unable to find gameplay effect [%s]."), *ULyraGameData::Get().DynamicTagGameplayEffect.GetAssetName());
		return;
	}
	/** Every set condition within this query must match in order for the query to match. i.e. individual query elements are ANDed together. */

	/**
	 * FGameplayEffectQuery: 
	 * 为了使该查询匹配成功，此查询中的每一个设定条件都必须匹配。也就是说，各个查询元素是通过“与”运算组合在一起的。  
	 */

	 /** Creates an effect query that will match if there are any common tags between the given tags and an ActiveGameplayEffect's owning tags */

	/**
	 * FGameplayEffectQuery::MakeQuery_MatchAnyOwningTags: 
	 * 创造一个有效查询，查询将匹配是否在给定标签和ActiveGameplayEffect的自身标签之间有任意共同标签。
	 */
	FGameplayEffectQuery Query = FGameplayEffectQuery::MakeQuery_MatchAnyOwningTags(FGameplayTagContainer(Tag));
	/** Matches on GameplayEffects with this definition */

	/**
	 * EffectDefinition: 匹配有此定义的游戏玩法效果。EffectDefinition是限制GameplayEffect的类类型
	 */
	Query.EffectDefinition = DynamicTagGE;
	Query.EffectDefinition = DynamicTagGE;

	/** Removes all active effects that match given query. StacksToRemove=-1 will remove all stacks. */

	/** RemoveActiveEffects: 针对给定参数移除所有激活的效果。StacksToRemove=-1将移除所有堆栈。 */
	RemoveActiveEffects(Query);
}

void ULyraAbilitySystemComponent::GetAbilityTargetData(const FGameplayAbilitySpecHandle AbilityHandle, FGameplayAbilityActivationInfo ActivationInfo, FGameplayAbilityTargetDataHandle& OutTargetDataHandle)
{
	/** Struct defining the cached data for a specific gameplay ability. This data is generally synchronized client->server in a network game. */

	/**
	 * FAbilityReplicatedDataCache:
	 * 定义具体的游戏玩法能力的缓存数据的结构体。这个数据在网络游戏中通常是从客户端同步到服务端。
	 */

	 /** Maps from an ability spec to the target data. Used to track replicated data and callbacks */

	/**
	 * AbilityTargetDataMap: 从能力规则到目标节点数据的映射。用于跟踪复制数据和回调。
	 */

	/** Used as a key for storing internal ability data */

	/** FGameplayAbilitySpecHandleAndPredictionKey: 用于作为存储内部能力数据的Key。 */
	TSharedPtr<FAbilityReplicatedDataCache> ReplicatedData = AbilityTargetDataMap.Find(FGameplayAbilitySpecHandleAndPredictionKey(AbilityHandle, ActivationInfo.GetActivationPredictionKey()));
	if (ReplicatedData.IsValid())
	{
		/** What elements this activation is targeting */

		/** TargetData: 激活所针对的目标节点是啥。 */
		OutTargetDataHandle = ReplicatedData->TargetData;
	}
}

